﻿#include "pch.h"
#include "brush.h"
#include "engine/renderd2d.h"
#include "common/winapi.h"
#include <common/Exception.h>

JOUI::UIBrush::UIBrush()
{
	br_CreateBrush(UIColor(0, 0, 0, 0));
}

JOUI::UIBrush::UIBrush(UIColor argb)
{
	br_CreateBrush(argb);
}
inline D2D1_EXTEND_MODE GetD2DExtendMode(JOUI::BrushModeEx mode)
{
	switch (mode)
	{
	case JOUI::BrushModeEx::None: return D2D1_EXTEND_MODE_CLAMP;
	case JOUI::BrushModeEx::Tile: return D2D1_EXTEND_MODE_WRAP;
	case JOUI::BrushModeEx::Mirror: return D2D1_EXTEND_MODE_MIRROR;
	default: return D2D1_EXTEND_MODE_CLAMP;
	}
}
JOUI::UIBrush::UIBrush(UICanvas* canvas_src, BrushModeEx extendmode, DWORD alpha)
{
	ID2D1DeviceContext* m_dc = (ID2D1DeviceContext*)canvas_src->GetContext(0);
	ID2D1Bitmap1* bitmap = (ID2D1Bitmap1*)canvas_src->GetContext(3);
	throw_if_false(m_dc, EE_NOREADY, L"渲染目标为空");

	//获取扩展模式
	D2D1_EXTEND_MODE mode = GetD2DExtendMode(extendmode);

	//生成属性
	D2D1_BRUSH_PROPERTIES bp = D2D1::BrushProperties(alpha / 255.0F);
	D2D1_BITMAP_BRUSH_PROPERTIES1 bbp = D2D1::BitmapBrushProperties1(
		mode, mode, D2D1_INTERPOLATION_MODE_LINEAR
	);
	//创建画刷
	throw_if_failed(
		m_dc->CreateBitmapBrush(
			bitmap, bbp, bp, (ID2D1BitmapBrush1**)&m_brush
		), L"创建位图画刷失败"
	);
}
JOUI::UIBrush::UIBrush(UIImage* hImage, INT mode, BrushModeEx extendmode, DWORD alpha)
{
	ID2D1Bitmap* m_d2d_bitmap = (ID2D1Bitmap*)hImage->GetContext();
	//获取扩展模式
	auto extend_mode = GetD2DExtendMode(extendmode);

	D2D1_RECT_F m_src_rect{};
	m_src_rect.left = m_src_rect.top = 0;
	m_src_rect.right = m_d2d_bitmap->GetSize().width;
	m_src_rect.bottom = m_d2d_bitmap->GetSize().height;
	//创建图像画刷
	throw_if_failed(
		FAILED(g_d2d_dc->CreateImageBrush(
			m_d2d_bitmap, D2D1::ImageBrushProperties(
				m_src_rect,
				extend_mode, extend_mode,
				(D2D1_INTERPOLATION_MODE)mode
			), D2D1::BrushProperties(alpha / 255.0F), (ID2D1ImageBrush**)&m_brush
		)), L"创建位图画刷失败");
}
void JOUI::UIBrush::SetImgTransformToRect(float Width, float Height, float left, float top, float right, float bottom)
{
	if (m_brush)
	{
		D2D1_MATRIX_3X2_F m_transform_src = D2D1::Matrix3x2F::Identity();
		D2D1_MATRIX_3X2_F m_transform_user = D2D1::Matrix3x2F::Identity();
		//获取最终目标矩形
		ExRectF dst_rect = ExRectF(left, top, right, bottom).Normalize();

		//计算缩放比例
		float scale_x = dst_rect.Width() / Width;
		float scale_y = dst_rect.Height() / Height;

		//生成变换矩阵
		ExMatrix3x2 transform;
		transform.Scale(scale_x, scale_y).Translate(left, top);

		//设置变换
		m_transform_user = MatrixEx(ExMatrix3x2::MakeScale(scale_x, scale_y).Translate(left, top));
		((ID2D1ImageBrush*)m_brush)->SetTransform(m_transform_src * m_transform_user);
	}
}
JOUI::UIBrush::UIBrush(FLOAT xStart, FLOAT yStart, FLOAT xEnd, FLOAT yEnd, UIColor crBegin, UIColor crEnd, BrushModeEx extendmode, BOOL isGamma1_0)
{
	UIColor arrStopPts[] = { crBegin ,crEnd };
	FLOAT arrINTPts[] = { 0, 1 };
	br_CreatGradientBrush(xStart, yStart, xEnd, yEnd, arrStopPts, arrINTPts, 2, extendmode, isGamma1_0);
}
JOUI::UIBrush::UIBrush(FLOAT xStart, FLOAT yStart, FLOAT xEnd, FLOAT yEnd, const UIColor* arrStopPts, const FLOAT* arrINT, INT cStopPts, BrushModeEx extendmode, BOOL isGamma1_0)
{
	br_CreatGradientBrush(xStart, yStart, xEnd, yEnd, arrStopPts, arrINT, cStopPts, extendmode, isGamma1_0);
}
void JOUI::UIBrush::SetLinearBeginPoint(float x, float y)
{
	if (m_brush)
	{
		D2D1_POINT_2F pt{ x, y };
		((ID2D1LinearGradientBrush*)m_brush)->SetStartPoint(pt);
	}
}
void JOUI::UIBrush::SetLinearEndPoint(float x, float y)
{
	if (m_brush)
	{
		D2D1_POINT_2F pt{ x, y };
		((ID2D1LinearGradientBrush*)m_brush)->SetEndPoint(pt);
	}
}
void JOUI::UIBrush::SetLinearPoints(const ExPointF* begin_point, const ExPointF* end_point)
{
	if (m_brush)
	{
		if (begin_point) {
			D2D1_POINT_2F pt{ begin_point->x, begin_point->y };
			((ID2D1LinearGradientBrush*)m_brush)->SetStartPoint(pt);
		}
		if (end_point) {
			D2D1_POINT_2F pt{ end_point->x, end_point->y };
			((ID2D1LinearGradientBrush*)m_brush)->SetEndPoint(pt);
		}
	}
}
JOUI::UIBrush::UIBrush(BOOL isGamma1_0, FLOAT x, FLOAT y, FLOAT radiusX, FLOAT radiusY, UIColor crBegin, UIColor crEnd, BrushModeEx extendmode)
{
	UIColor arrStopPts[] = { crBegin ,crEnd };
	FLOAT arrINTPts[] = { 0, 1 };
	br_CreatRadialBrush(x, y, radiusX, radiusY, arrStopPts, arrINTPts, 2, {}, extendmode, isGamma1_0);
}
JOUI::UIBrush::UIBrush(FLOAT x, FLOAT y, FLOAT radiusX, FLOAT radiusY, const UIColor* arrStopPts, const FLOAT* arrINT, INT cStopPts, POINT gradientOriginOffset, BrushModeEx extendmode, BOOL isGamma1_0)
{
	br_CreatRadialBrush(x, y, radiusX, radiusY, arrStopPts, arrINT, cStopPts, gradientOriginOffset, extendmode, isGamma1_0);
}
void JOUI::UIBrush::SetRadialBoundsRect(float left, float top, float right, float bottom)
{
	if (m_brush)
	{
		ExRectF m_bounds = ExRectF(left, top, right, bottom).Normalize();
		((ID2D1RadialGradientBrush*)m_brush)->SetRadiusX(m_bounds.Width() / 2);
		((ID2D1RadialGradientBrush*)m_brush)->SetRadiusY(m_bounds.Height() / 2);
		((ID2D1RadialGradientBrush*)m_brush)->SetCenter(D2D1::Point2F(m_bounds.GetHorzCenter(), m_bounds.GetVertCenter()));
	}
}
void JOUI::UIBrush::SetRadialCenter(FLOAT offsetX, FLOAT offsetY)
{
	if (m_brush)
		((ID2D1RadialGradientBrush*)m_brush)->SetCenter({ offsetX, offsetY });
}
void JOUI::UIBrush::SetRadialCenterOffset(float horz, float vert)
{
	if (m_brush)
		((ID2D1RadialGradientBrush*)m_brush)->SetGradientOriginOffset(D2D1::Point2F(horz, vert));
}

void JOUI::UIBrush::SetColor(UIColor argb)
{
	if (m_brush)
		((ID2D1SolidColorBrush*)m_brush)->SetColor(argb.GetDxObject());
}
void JOUI::UIBrush::GetColor(D2D1_COLOR_F& lpColor)
{
	if (m_brush)
		lpColor = ((ID2D1SolidColorBrush*)m_brush)->GetColor();
}
void JOUI::UIBrush::GetColor(UIColor& lpColor)
{
	if (m_brush)
		lpColor = UIColor(((ID2D1SolidColorBrush*)m_brush)->GetColor());
}
void JOUI::UIBrush::SetOpacity(FLOAT alpha)
{
	if (m_brush)
		((ID2D1SolidColorBrush*)m_brush)->SetOpacity(alpha);
}
void JOUI::UIBrush::SetTransForm(ExMatrix matrix)
{
	if (m_brush)
	{
		D2D1_MATRIX_3X2_F mx = MatrixEx(matrix);
		((ID2D1ImageBrush*)m_brush)->SetTransform(mx);
	}
}
void JOUI::UIBrush::GetTransForm(ExMatrix* matrix)
{
	if (m_brush && matrix)
		((ID2D1ImageBrush*)m_brush)->GetTransform((D2D1_MATRIX_3X2_F*)matrix);
}

LPVOID JOUI::UIBrush::GetContext()
{
	return m_brush;
}

JOUI::UIBrush::~UIBrush()
{
	if (m_brush)
		((ID2D1Brush*)m_brush)->Release();
}

void JOUI::UIBrush::br_CreateBrush(UIColor argb)
{
	throw_if_failed(
		g_d2d_dc->CreateSolidColorBrush(argb.GetDxObject(), (ID2D1SolidColorBrush**)&m_brush),
		L"纯色画刷创建失败"
	);
}

void JOUI::UIBrush::br_CreatGradientBrush(FLOAT xStart, FLOAT yStart, FLOAT xEnd, FLOAT yEnd, const UIColor* arrStopPts, const FLOAT* arrINT, INT cStopPts, BrushModeEx extendmode, BOOL isGamma1_0)
{
	if (cStopPts < 2)
	{
		return;
	}
	ID2D1GradientStopCollection* gradientStopCollection = nullptr;
	D2D1_GRADIENT_STOP* gradientStops = (D2D1_GRADIENT_STOP*)malloc(cStopPts * sizeof(D2D1_GRADIENT_STOP));
	D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES gradientProperties{};
	if (gradientStops)
	{
		for (INT i = 0; i < cStopPts; i++)
		{
			gradientStops[i].color = arrStopPts[i].GetDxObject();
			gradientStops[i].position = arrINT[i];
		}
		//获取扩展模式
		D2D1_EXTEND_MODE extend_mode = GetD2DExtendMode(extendmode);
		g_d2d_dc->CreateGradientStopCollection(gradientStops, cStopPts, isGamma1_0 ? D2D1_GAMMA_1_0 : D2D1_GAMMA_2_2, extend_mode, &gradientStopCollection);

		gradientProperties.startPoint.x = xStart;
		gradientProperties.startPoint.y = yStart;
		gradientProperties.endPoint.x = xEnd;
		gradientProperties.endPoint.y = yEnd;
		if (gradientStopCollection)
		{
			g_d2d_dc->CreateLinearGradientBrush(&gradientProperties, NULL, gradientStopCollection, (ID2D1LinearGradientBrush**)&m_brush);
		}
		gradientStopCollection->Release();
		free(gradientStops);
	}
}

void JOUI::UIBrush::br_CreatRadialBrush(FLOAT x, FLOAT y, FLOAT radiusX, FLOAT radiusY, const UIColor* arrStopPts, const FLOAT* arrINT, INT cStopPts, POINT gradientOriginOffset, BrushModeEx extendmode, BOOL isGamma1_0)
{
	if (cStopPts < 2)
	{
		return;
	}
	ID2D1GradientStopCollection* gradientStopCollection = nullptr;
	D2D1_GRADIENT_STOP* gradientStops = (D2D1_GRADIENT_STOP*)malloc(cStopPts * sizeof(D2D1_GRADIENT_STOP));
	D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES gradientProperties{};
	if (gradientStops)
	{
		for (INT i = 0; i < cStopPts; i++)
		{
			gradientStops[i].color = arrStopPts[i].GetDxObject();
			gradientStops[i].position = arrINT[i];
		}
		//获取扩展模式
		D2D1_EXTEND_MODE extend_mode = GetD2DExtendMode(extendmode);
		g_d2d_dc->CreateGradientStopCollection(gradientStops, cStopPts, isGamma1_0 ? D2D1_GAMMA_1_0 : D2D1_GAMMA_2_2, extend_mode, &gradientStopCollection);

		gradientProperties.center.x = x;
		gradientProperties.center.y = y;
		gradientProperties.radiusX = radiusX;
		gradientProperties.radiusY = radiusY;
		gradientProperties.gradientOriginOffset.x = gradientOriginOffset.x;
		gradientProperties.gradientOriginOffset.y = gradientOriginOffset.y;
		if (gradientStopCollection)
		{
			g_d2d_dc->CreateRadialGradientBrush(&gradientProperties, NULL, gradientStopCollection, (ID2D1RadialGradientBrush**)&m_brush);
		}
		gradientStopCollection->Release();
		free(gradientStops);
	}
}
